#include "ei_os.h"
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/version.h>
#include <linux/atomic.h>
#include <linux/slab.h>
#include <asm/barrier.h>
#include <asm/cacheflush.h>
#include <linux/printk.h>
#include <linux/kthread.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/dmaengine.h>
#include <linux/interrupt.h>
#include <linux/kfifo.h>
#include <linux/random.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/kthread.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/rtc.h>
#include <linux/sched/clock.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

#include "os_inner.h"

static spinlock_t dev_lock;
static spinlock_t mem_lock;

/* synchronization */
int os_atomic_init(os_atomic_t *v)
{
	atomic_t *p = NULL;

	if (v == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (atomic_t *) os_kmalloc(sizeof(atomic_t), os_gfp_kernel);
	if (p == NULL) {
		os_printk("%s - os_kmalloc error!\n", __func__);
		return -1;
	}
	memset(p, 0, sizeof(atomic_t));
	v->atomic = p;

	return 0;
}
EXPORT_SYMBOL(os_atomic_init);

void os_atomic_destroy(os_atomic_t *v)
{
	os_kfree(v->atomic);
	v->atomic = NULL;
}
EXPORT_SYMBOL(os_atomic_destroy);

int os_atomic_read(os_atomic_t *v)
{
	atomic_t *p = NULL;

	if (v == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (atomic_t *) (v->atomic);

	return atomic_read(p);
}
EXPORT_SYMBOL(os_atomic_read);

void os_atomic_set(os_atomic_t *v, int i)
{
	atomic_t *p = NULL;

	p = (atomic_t *) (v->atomic);
	atomic_set(p, i);
}
EXPORT_SYMBOL(os_atomic_set);

int os_atomic_inc_return(os_atomic_t *v)
{
	atomic_t *p = NULL;

	if (v == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (atomic_t *) (v->atomic);
	return atomic_inc_return(p);
}
EXPORT_SYMBOL(os_atomic_inc_return);

int os_atomic_dec_return(os_atomic_t *v)
{
	atomic_t *p = NULL;

	if (v == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (atomic_t *) (v->atomic);
	return atomic_dec_return(p);
}
EXPORT_SYMBOL(os_atomic_dec_return);

int os_atomic_add_return(int i, os_atomic_t *v)
{
	atomic_t *p = NULL;

	if (v == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (atomic_t *) (v->atomic);
	return atomic_add_return(i, p);
}
EXPORT_SYMBOL(os_atomic_add_return);

int os_atomic_sub_return(int i, os_atomic_t *v)
{
	atomic_t *p = NULL;

	if (v == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (atomic_t *) (v->atomic);
	return atomic_sub_return(i, p);
}
EXPORT_SYMBOL(os_atomic_sub_return);

int os_mutex_init(os_mutex_t *mutex)
{
	struct mutex *p = NULL;

	if (mutex == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = os_kmalloc(sizeof(struct mutex), os_gfp_kernel);
	if (p == NULL) {
		os_printk("%s - os_kmalloc error!\n", __func__);
		return -1;
	}
	mutex_init(p);
	mutex->mutex = p;

	return 0;
}
EXPORT_SYMBOL(os_mutex_init);

int os_mutex_lock(os_mutex_t *mutex)
{
	struct mutex *p = NULL;

	if (mutex == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct mutex *) (mutex->mutex);
	mutex_lock(p);

	return 0;
}
EXPORT_SYMBOL(os_mutex_lock);

int os_mutex_lock_interruptible(os_mutex_t *mutex)
{
	struct mutex *p = NULL;

	if (mutex == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct mutex *) (mutex->mutex);
	return mutex_lock_interruptible(p);
}
EXPORT_SYMBOL(os_mutex_lock_interruptible);

int os_mutex_trylock(os_mutex_t *mutex)
{
	struct mutex *p = NULL;

	if (mutex == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct mutex *) (mutex->mutex);

	return mutex_trylock(p);
}
EXPORT_SYMBOL(os_mutex_trylock);

void os_mutex_unlock(os_mutex_t *mutex)
{
	struct mutex *p = NULL;

	p = (struct mutex *) (mutex->mutex);

	mutex_unlock(p);
}
EXPORT_SYMBOL(os_mutex_unlock);

void os_mutex_destroy(os_mutex_t *mutex)
{
	struct mutex *p = NULL;

	if (mutex == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (struct mutex *) (mutex->mutex);
		os_kfree(p);
		mutex->mutex = NULL;
	}
}
EXPORT_SYMBOL(os_mutex_destroy);

int os_sema_init(os_semaphore_t *sem, int val)
{
	struct semaphore *p = NULL;

	if (sem == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = os_kmalloc(sizeof(struct semaphore), os_gfp_kernel);
	if (p == NULL) {
		os_printk("%s - os_kmalloc error!\n", __func__);
		return -1;
	}
	sema_init(p, val);
	sem->sem = p;

	return 0;
}
EXPORT_SYMBOL(os_sema_init);

void os_down(os_semaphore_t *sem)
{
	struct semaphore *p = NULL;

	if (sem == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (struct semaphore *) (sem->sem);
		down(p);
	}
}
EXPORT_SYMBOL(os_down);

 /* @timeout: timeout value in jiffies */
int os_down_timeout(os_semaphore_t *sem, long timeout)
{
	struct semaphore *p = NULL;

	if (sem == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct semaphore *) (sem->sem);

	return down_timeout(p, timeout);
}
EXPORT_SYMBOL(os_down_timeout);

 /* down_killable - acquire the semaphore unless killed */
int os_down_killable(os_semaphore_t *sem)
{
	struct semaphore *p = NULL;

	if (sem == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct semaphore *) (sem->sem);

	return down_killable(p);
}
EXPORT_SYMBOL(os_down_killable);

int os_down_trylock(os_semaphore_t *sem)
{
	struct semaphore *p = NULL;

	if (sem == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct semaphore *) (sem->sem);

	return down_trylock(p);
}
EXPORT_SYMBOL(os_down_trylock);

int os_down_interruptible(os_semaphore_t *sem)
{
	struct semaphore *p = NULL;

	if (sem == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct semaphore *) (sem->sem);
	return down_interruptible(p);
}
EXPORT_SYMBOL(os_down_interruptible);

void os_up(os_semaphore_t *sem)
{
	struct semaphore *p = NULL;

	if (sem == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (struct semaphore *) (sem->sem);
		up(p);
	}
}
EXPORT_SYMBOL(os_up);

void os_sema_destroy(os_semaphore_t *sem)
{
	struct semaphore *p = NULL;

	if (sem == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (struct semaphore *) (sem->sem);
		os_kfree(p);
		sem->sem = NULL;
	}
}
EXPORT_SYMBOL(os_sema_destroy);

int os_spin_lock_init(os_spinlock_t *lock)
{
	spinlock_t *p = NULL;

	if (lock == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (spinlock_t *) os_kmalloc(sizeof(spinlock_t), os_gfp_kernel);
	if (p == NULL) {
		os_printk("%s - os_kmalloc error!\n", __func__);
		return -1;
	}
	spin_lock_init(p);
	lock->lock = p;

	return 0;
}
EXPORT_SYMBOL(os_spin_lock_init);

void os_spin_lock(os_spinlock_t *lock)
{
	spinlock_t *p = NULL;

	if (lock == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (spinlock_t *) (lock->lock);
		spin_lock(p);
	}
}
EXPORT_SYMBOL(os_spin_lock);

int os_spin_trylock(os_spinlock_t *lock)
{
	spinlock_t *p = NULL;

	if (lock == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (spinlock_t *) (lock->lock);
	return spin_trylock(p);
}
EXPORT_SYMBOL(os_spin_trylock);

void os_spin_unlock(os_spinlock_t *lock)
{
	spinlock_t *p = NULL;

	if (lock == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (spinlock_t *) (lock->lock);
		spin_unlock(p);
	}
}
EXPORT_SYMBOL(os_spin_unlock);

void os_spin_lock_irqsave(os_spinlock_t *lock, unsigned long *flags)
{
	spinlock_t *p = NULL;
	unsigned long f;

	if (lock == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (spinlock_t *) (lock->lock);
		spin_lock_irqsave(p, f);
		*flags = f;
	}
}
EXPORT_SYMBOL(os_spin_lock_irqsave);

void os_spin_unlock_irqrestore(os_spinlock_t *lock, unsigned long *flags)
{
	spinlock_t *p = NULL;
	unsigned long f;

	if (lock == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (spinlock_t *) (lock->lock);
		f = *flags;
		spin_unlock_irqrestore(p, f);
	}
}
EXPORT_SYMBOL(os_spin_unlock_irqrestore);

void os_spin_lock_destroy(os_spinlock_t *lock)
{
	spinlock_t *p = NULL;

	if (lock == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (spinlock_t *) (lock->lock);
		os_kfree(p);
		lock->lock = NULL;
	}
}
EXPORT_SYMBOL(os_spin_lock_destroy);

int os_wait_init(os_wait_t *wait)
{
	wait_queue_head_t *wq = NULL;

	if (wait == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	wq = (wait_queue_head_t *) os_kmalloc(sizeof(wait_queue_head_t),
					   os_gfp_kernel);
	if (wq == NULL) {
		os_printk("%s - os_kmalloc error!\n", __func__);
		return -1;
	}
	init_waitqueue_head(wq);
	wait->wait = wq;

	return 0;
}
EXPORT_SYMBOL(os_wait_init);

int os_wait_interruptible(os_wait_t *wait, os_wait_cond_func_t func,
			  void *param)
{
	wait_queue_head_t *wq = NULL;
	long ret = 0;

	if (wait == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}

	if (func == NULL) {
		os_printk("%s - func invalid!\n", __func__);
		return -1;
	}

	wq = (wait_queue_head_t *) (wait->wait);
	if (wq == NULL) {
		os_printk("%s - wait->wait is NULL!\n", __func__);
		return -1;
	}

	ret = wait_event_interruptible(*wq, func(param));

	return ret;
}
EXPORT_SYMBOL(os_wait_interruptible);

int os_wait_uninterruptible(os_wait_t *wait, os_wait_cond_func_t func,
			    void *param)
{
	wait_queue_head_t *wq = NULL;
	long ret = 0;

	if (wait == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}

	if (func == NULL) {
		os_printk("%s - func invalid!\n", __func__);
		return -1;
	}

	wq = (wait_queue_head_t *) (wait->wait);
	if (wq == NULL) {
		os_printk("%s - wait->wait is NULL!\n", __func__);
		return -1;
	}

	wait_event(*wq, func(param));

	return ret;
}
EXPORT_SYMBOL(os_wait_uninterruptible);

int os_wait_timeout_interruptible(os_wait_t *wait, os_wait_cond_func_t func,
				  void *param, unsigned long timeout_ms)
{
	wait_queue_head_t *wq = NULL;
	long ret = timeout_ms;

	if (wait == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}

	if (func == NULL) {
		os_printk("%s - func invalid!\n", __func__);
		return -1;
	}

	wq = (wait_queue_head_t *) (wait->wait);
	if (wq == NULL) {
		os_printk("%s - wait->wait is NULL!\n", __func__);
		return -1;
	}

	ret = wait_event_interruptible_timeout(*wq, func(param),
				msecs_to_jiffies(timeout_ms));

	return ret;
}
EXPORT_SYMBOL(os_wait_timeout_interruptible);

int os_wait_timeout_uninterruptible(os_wait_t *wait, os_wait_cond_func_t func,
				    void *param, unsigned long timeout_ms)
{
	wait_queue_head_t *wq = NULL;
	long ret = timeout_ms;

	if (wait == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}

	if (func == NULL) {
		os_printk("%s - func invalid!\n", __func__);
		return -1;
	}

	wq = (wait_queue_head_t *) (wait->wait);
	if (wq == NULL) {
		os_printk("%s - wait->wait is NULL!\n", __func__);
		return -1;
	}

	ret = wait_event_timeout(*wq, func(param), msecs_to_jiffies(timeout_ms));

	return ret;
}
EXPORT_SYMBOL(os_wait_timeout_uninterruptible);

void os_wakeup(os_wait_t *wait)
{
	wait_queue_head_t *wq = NULL;

	wq = (wait_queue_head_t *) (wait->wait);
	if (wq == NULL) {
		os_printk("%s - wait->wait is NULL!\n", __func__);
		return;
	}
	wake_up_all(wq);
}
EXPORT_SYMBOL(os_wakeup);

void os_wait_destroy(os_wait_t *wait)
{
	wait_queue_head_t *wq = NULL;

	wq = (wait_queue_head_t *) (wait->wait);
	if (wq == NULL) {
		os_printk("%s - wait->wait is NULL!\n", __func__);
		return;
	}
	os_kfree(wq);
	wait->wait = NULL;
}
EXPORT_SYMBOL(os_wait_destroy);
/* memory */

/**
 * for device mapping
 */
void *os_ioremap(unsigned long phys_addr, unsigned long size)
{
	return ioremap(phys_addr, size);
}
EXPORT_SYMBOL(os_ioremap);

/**
 * ioremap_nocache is the same as ioremap for device register access.
 */
void *os_ioremap_nocache(unsigned long phys_addr, unsigned long size)
{
	return ioremap_nocache(phys_addr, size);
}
EXPORT_SYMBOL(os_ioremap_nocache);

/**
 * for normal memory mapping
 */
void *os_ioremap_cached(unsigned long phys_addr, unsigned long size)
{
	return ioremap_cache(phys_addr, size);
}
EXPORT_SYMBOL(os_ioremap_cached);

void os_iounmap(void *addr)
{
	iounmap(addr);
}
EXPORT_SYMBOL(os_iounmap);

unsigned long os_copy_from_user(void *to, const void *from, unsigned long n)
{
	return copy_from_user(to, from, n);
}
EXPORT_SYMBOL(os_copy_from_user);

unsigned long os_copy_to_user(void *to, const void *from, unsigned long n)
{
	return copy_to_user(to, from, n);
}
EXPORT_SYMBOL(os_copy_to_user);

int os_access_ok(int type, const void *addr, unsigned long size)
{
	return access_ok(type, addr, size);
}
EXPORT_SYMBOL(os_access_ok);

#ifdef OS_MEM_LEAK_DBG
static os_mem_blk_info_t g_info[OS_FUNC_ITEM_SIZE] = {{0}};
#endif

static os_mem_stats_t g_mem_stats =
{
	.vmalloc_cnt = 0,
	.vzalloc_cnt = 0,
	.vfree_cnt = 0,
	.kmalloc_cnt = 0,
	.kzalloc_cnt = 0,
	.kfree_cnt = 0,
#ifdef OS_MEM_LEAK_DBG
	.info = g_info,
#else
	.info = NULL,
#endif
};

void *os_vmalloc(unsigned long size)
{
	spin_lock(&mem_lock);
	g_mem_stats.vmalloc_cnt++;
	if (g_mem_stats.vmalloc_max < size)
		g_mem_stats.vmalloc_max = size;
	spin_unlock(&mem_lock);

	return vmalloc(size);
}
EXPORT_SYMBOL(os_vmalloc);

void *os_vzalloc(unsigned long size)
{
	spin_lock(&mem_lock);
	g_mem_stats.vzalloc_cnt++;
	if (g_mem_stats.vzalloc_max < size)
		g_mem_stats.vzalloc_max = size;
	spin_unlock(&mem_lock);

	return vzalloc(size);
}
EXPORT_SYMBOL(os_vzalloc);

void os_vfree(const void *addr)
{
	spin_lock(&mem_lock);
	g_mem_stats.vfree_cnt++;
	spin_unlock(&mem_lock);

	vfree(addr);
}
EXPORT_SYMBOL(os_vfree);

void *__os_kmalloc(unsigned long size, unsigned int os_gfp_flag, const char *func_name, const int line)
{
	void *addr = NULL;

	if (os_gfp_flag == os_gfp_kernel)
		addr = kmalloc(size, GFP_KERNEL);
	else if (os_gfp_flag == os_gfp_atomic)
		addr = kmalloc(size, GFP_ATOMIC);
	else
		addr = NULL;

	spin_lock(&mem_lock);
#ifdef OS_MEM_LEAK_DBG
	{
		int i = 0;
		for (i = 0; i < OS_FUNC_ITEM_SIZE; ++i) {
			if(g_mem_stats.info[i].busy == 0) {
				os_strncpy(g_mem_stats.info[i].func_name, func_name, OS_FUNC_NAME_SIZE - 1);
				g_mem_stats.info[i].line = line;
				g_mem_stats.info[i].addr = addr;
				g_mem_stats.info[i].size = size;
				g_mem_stats.info[i].busy = 1;
				break;
			}
		}
	}
#endif
	if (g_mem_stats.kmalloc_max < size)
		g_mem_stats.kmalloc_max = size;

	g_mem_stats.kmalloc_cnt++;

	spin_unlock(&mem_lock);

	return addr;
}
EXPORT_SYMBOL(__os_kmalloc);

void *__os_kzalloc(unsigned long size, unsigned int os_gfp_flag, const char *func_name, const int line)
{
	void *addr = NULL;

	if (os_gfp_flag == os_gfp_kernel)
		addr = kzalloc(size, GFP_KERNEL);
	else if (os_gfp_flag == os_gfp_atomic)
		addr = kzalloc(size, GFP_ATOMIC);
	else
		addr = NULL;

	spin_lock(&mem_lock);
#ifdef OS_MEM_LEAK_DBG
	{
		int i = 0;
		for (i = 0; i < OS_FUNC_ITEM_SIZE; ++i) {
			if(g_mem_stats.info[i].busy == 0) {
				os_strncpy(g_mem_stats.info[i].func_name, func_name, OS_FUNC_NAME_SIZE - 1);
				g_mem_stats.info[i].line = line;
				g_mem_stats.info[i].addr = addr;
				g_mem_stats.info[i].size = size;
				g_mem_stats.info[i].busy = 1;
				break;
			}
		}
	}
#endif
	if (g_mem_stats.kzalloc_max < size)
		g_mem_stats.kzalloc_max = size;
	g_mem_stats.kzalloc_cnt++;
	spin_unlock(&mem_lock);

	return addr;
}
EXPORT_SYMBOL(__os_kzalloc);

void __os_kfree(const void *addr, const char *func_name, const int line)
{

	spin_lock(&mem_lock);
#ifdef OS_MEM_LEAK_DBG
	{
		int i = 0;
		for (i = 0; i < OS_FUNC_ITEM_SIZE; ++i) {
			if(addr == g_mem_stats.info[i].addr) {
				g_mem_stats.info[i].busy = 0;
				break;
			}
		}
	}
#endif
	g_mem_stats.kfree_cnt++;
	spin_unlock(&mem_lock);

	kfree(addr);
}
EXPORT_SYMBOL(__os_kfree);

void os_get_mem_stats(os_mem_stats_t *memstats)
{
	spin_lock(&mem_lock);
	*memstats = g_mem_stats;
	spin_unlock(&mem_lock);
}
EXPORT_SYMBOL(os_get_mem_stats);

void os_mb(void)
{
	mb();
}
EXPORT_SYMBOL(os_mb);

void os_rmb(void)
{
	rmb();
}
EXPORT_SYMBOL(os_rmb);

void os_wmb(void)
{
	wmb();
}
EXPORT_SYMBOL(os_wmb);

void os_smp_mb(void)
{
	smp_mb();
}
EXPORT_SYMBOL(os_smp_mb);

void os_smp_rmb(void)
{
	smp_rmb();
}
EXPORT_SYMBOL(os_smp_rmb);

void os_smp_wmb(void)
{
	smp_wmb();
}
EXPORT_SYMBOL(os_smp_wmb);

void os_isb(void)
{
	isb();
}
EXPORT_SYMBOL(os_isb);

void os_dsb(void)
{
#if defined(CONFIG_64BIT)
	dsb(sy);
#else
	dsb();
#endif
}
EXPORT_SYMBOL(os_dsb);

void os_dmb(void)
{
#if defined(CONFIG_64BIT)
	dmb(sy);
#else
	dmb();
#endif
}
EXPORT_SYMBOL(os_dmb);

void os_flush_dcache_area(void *kvaddr, unsigned long phys_addr, int size)
{
#if defined(CONFIG_64BIT)
	__flush_dcache_area((void *)kvaddr, size);
#else
	__cpuc_flush_dcache_area(kvaddr, size);
#endif
}
EXPORT_SYMBOL(os_flush_dcache_area);

void os_invalid_dcache_area(void *kvaddr, unsigned long phys_addr, int size)
{
#if defined(CONFIG_64BIT)
	__flush_dcache_area((void *)kvaddr, size);
#else
	__cpuc_flush_dcache_area(kvaddr, size);
#endif
}
EXPORT_SYMBOL(os_invalid_dcache_area);

/*** clock ***/
int os_platform_clk_prepare_enable_all(void *dev)
{
	struct of_phandle_args clkspec;
	int index, rc = 0, num_clks;
	struct clk *clk;
	struct platform_device *pdev = (struct platform_device *)dev;
	struct device_node *node;

	if (!pdev) {
		pr_err("invalid parameter!\n");
		rc = -1;
		goto err;
	}
	node = pdev->dev.of_node;

	num_clks = of_count_phandle_with_args(node, "assigned-clocks",
						 "#clock-cells");
	if (num_clks < 0)
		pr_err("clk: invalid value of assigned-clocks property at %pOF\n",
		       node);

	for (index = 0; index < num_clks; index++) {
		rc = of_parse_phandle_with_args(node, "assigned-clocks",
					"#clock-cells", index, &clkspec);
		if (rc < 0)
			goto err;
		clk = of_clk_get_from_provider(&clkspec);
		if (IS_ERR(clk)) {
			if (PTR_ERR(clk) != -EPROBE_DEFER)
				pr_warn("clk: couldn't get assigned clock %d for %pOF\n",
					index, node);
			rc = PTR_ERR(clk);
			goto err;
		}

		rc = clk_prepare_enable(clk);
		if (rc < 0)
			pr_err("clk: failed to prepare enable %s: %d\n",
			       __clk_get_name(clk), rc);
		clk_put(clk);
	}
	return 0;
err:
	return rc;
}
EXPORT_SYMBOL(os_platform_clk_prepare_enable_all);

int os_platform_clk_disable_unprepare_all(void *dev)
{
	struct of_phandle_args clkspec;
	int index, rc = 0, num_clks;
	struct clk *clk;
	struct platform_device *pdev = (struct platform_device *)dev;
	struct device_node *node;

	if (!pdev) {
		pr_err("invalid parameter!\n");
		rc = -1;
		goto err;
	}
	node = pdev->dev.of_node;

	num_clks = of_count_phandle_with_args(node, "assigned-clocks",
						 "#clock-cells");
	if (num_clks < 0)
		pr_err("clk: invalid value of assigned-clocks property at %pOF\n",
		       node);

	for (index = num_clks - 1; index >= 0; index--) {
		rc = of_parse_phandle_with_args(node, "assigned-clocks",
					"#clock-cells", index, &clkspec);
		if (rc < 0)
			goto err;
		clk = of_clk_get_from_provider(&clkspec);
		if (IS_ERR(clk)) {
			if (PTR_ERR(clk) != -EPROBE_DEFER)
				pr_warn("clk: couldn't get assigned clock %d for %pOF\n",
					index, node);
			rc = PTR_ERR(clk);
			goto err;
		}

		clk_disable_unprepare(clk);

		clk_put(clk);
	}
	return 0;
err:
	return rc;
}
EXPORT_SYMBOL(os_platform_clk_disable_unprepare_all);

static struct clk * __os_platform_clk_get(void *dev, int index)
{
	struct of_phandle_args clkspec;
	struct platform_device *pdev = (struct platform_device *)dev;
	struct device_node *node;
	struct clk *clk = NULL;
	int rc, num_clks;

	if (!pdev) {
		pr_err("invalid parameter!\n");
		goto err;
	}
	node = pdev->dev.of_node;

	num_clks = of_count_phandle_with_args(node, "assigned-clocks",
						 "#clock-cells");
	if (num_clks < 0) {
		pr_err("clk: invalid value of assigned-clocks property for %s\n",
		       pdev->name);
		goto err;
	}

	if (index >= num_clks) {
		pr_err("%s clk: index(%d) is out of range(%d)\n",
		       pdev->name, index, num_clks - 1);
		goto err;
	}

	rc = of_parse_phandle_with_args(node, "assigned-clocks",
				"#clock-cells", index, &clkspec);
	if (rc < 0)
		goto err;
	clk = of_clk_get_from_provider(&clkspec);
	if (IS_ERR_OR_NULL(clk)) {
		if (PTR_ERR(clk) != -EPROBE_DEFER)
			pr_warn("clk: couldn't get assigned clock %d for %s\n",
				index, node->name);
		goto err;
	}

err:
	return clk;
}

int os_platform_clk_prepare_enable(void *dev, int index)
{
	struct clk *clk = NULL;
	int rc = 0;

	clk = __os_platform_clk_get(dev, index);
	if (IS_ERR_OR_NULL(clk)) {
		rc = PTR_ERR(clk);
		goto err;
	}

	rc = clk_prepare_enable(clk);
	if (rc < 0)
		pr_err("clk: failed to prepare enable %s: %d\n",
				__clk_get_name(clk), rc);
	clk_put(clk);

err:
	return rc;
}
EXPORT_SYMBOL(os_platform_clk_prepare_enable);

int os_platform_clk_disable_unprepare(void *dev, int index)
{
	struct clk *clk = NULL;
	int rc = 0;

	clk = __os_platform_clk_get(dev, index);
	if (IS_ERR_OR_NULL(clk)) {
		rc = PTR_ERR(clk);
		goto err;
	}

	clk_disable_unprepare(clk);
	clk_put(clk);

err:
	return rc;
}
EXPORT_SYMBOL(os_platform_clk_disable_unprepare);

int os_platform_clk_set_rate(void *dev, int index, unsigned long rate)
{
	struct clk *clk = NULL;
	int rc = 0;

	clk = __os_platform_clk_get(dev, index);
	if (IS_ERR_OR_NULL(clk)) {
		rc = PTR_ERR(clk);
		goto err;
	}

	rc = clk_set_rate(clk, rate);
	if (rc < 0)
		pr_err("clk: failed to prepare enable %s: %d\n",
				__clk_get_name(clk), rc);
	clk_put(clk);

err:
	return rc;
}
EXPORT_SYMBOL(os_platform_clk_set_rate);

unsigned long os_platform_clk_get_rate(void *dev, int index)
{
	struct clk *clk = NULL;
	int rc = 0;
	unsigned long rate = 0;

	clk = __os_platform_clk_get(dev, index);
	if (IS_ERR_OR_NULL(clk)) {
		rc = PTR_ERR(clk);
		goto err;
	}

	rate = clk_get_rate(clk);
	clk_put(clk);

err:
	return rate;
}
EXPORT_SYMBOL(os_platform_clk_get_rate);

int os_platform_clk_set_parent_rate(void *dev, int index, unsigned long rate)
{
	struct clk *clk = NULL, *pclk = NULL;
	int rc = 0;
	struct platform_device *pdev = (struct platform_device *)dev;

	clk = __os_platform_clk_get(dev, index);
	if (IS_ERR_OR_NULL(clk)) {
		rc = PTR_ERR(clk);
		goto err;
	}
	pclk = clk_get_parent(clk);
	if (IS_ERR_OR_NULL(pclk)) {
		pr_err("get parent clk %d fail for %s\n", index, pdev->name);
		rc = -1;
		goto err;
	}

	rc = clk_set_rate(pclk, rate);
	clk_put(clk);

err:
	return rc;
}
EXPORT_SYMBOL(os_platform_clk_set_parent_rate);

unsigned long os_platform_clk_get_parent_rate(void *dev, int index)
{
	struct clk *clk = NULL, *pclk = NULL;
	int rc = 0;
	struct platform_device *pdev = (struct platform_device *)dev;
	unsigned long rate = 0;

	clk = __os_platform_clk_get(dev, index);
	if (IS_ERR_OR_NULL(clk)) {
		rc = PTR_ERR(clk);
		goto err;
	}
	pclk = clk_get_parent(clk);
	if (IS_ERR_OR_NULL(pclk)) {
		pr_err("get parent clk %d fail for %s\n", index, pdev->name);
		rc = -1;
		goto err;
	}

	rate = clk_get_rate(pclk);
	clk_put(clk);

err:
	return rate;
}
EXPORT_SYMBOL(os_platform_clk_get_parent_rate);

/* log */
int os_printk(const char *fmt, ...)
{
	va_list args;
	int r;

	va_start(args, fmt);
	r = vprintk(fmt, args);
	va_end(args);

	return r;
}
EXPORT_SYMBOL(os_printk);

void os_panic(const char *fmt, const char *fun, int line, const char *cond)
{
	panic(fmt, fun, line, cond);
}
EXPORT_SYMBOL(os_panic);

#define OS_LOG_NAME		"log_main"

extern ssize_t logger_kernel_write(char *name, char *buf,
			   size_t count, loff_t *pos);

int os_log_write(char *buf, unsigned int count)
{
#if defined(CONFIG_ANDROID_LOGGER)
    return logger_kernel_write(OS_LOG_NAME, buf, count, 0);
#else
    /*                skip level,       skip level and mod name */
    os_printk("[%s] %s", buf + 1, buf + 1 + strlen(buf + 1) + 1);
#endif
}
EXPORT_SYMBOL(os_log_write);

/*** dma ***/
os_dma_chan_t *os_dma_channel_request(const char *name)
{
	os_dma_chan_t *p = NULL;
	dma_cap_mask_t mask;

	dma_cap_zero(mask);
	dma_cap_set(DMA_SLAVE, mask);

	p = os_kzalloc(sizeof(os_dma_chan_t), os_gfp_kernel);
	if (p == NULL) {
		os_printk("%s - malloc fail!\n", __func__);
		goto err;
	}

	p->dma_chan = (void *)dma_request_channel(mask, NULL, NULL);
	if (!p->dma_chan) {
		os_printk("%s - request error!\n", __func__);
		goto err;
	}

	return p;

err:
	os_kfree(p);

	return NULL;
}
EXPORT_SYMBOL(os_dma_channel_request);

int os_dma_channel_release(os_dma_chan_t *chan)
{
	struct dma_chan *p = NULL;

	if (chan == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct dma_chan *) (chan->dma_chan);
	dma_release_channel(p);

	os_kfree(chan);

	return 0;
}
EXPORT_SYMBOL(os_dma_channel_release);

int os_dma_channel_config(os_dma_chan_t *chan, os_dma_config_t *cfg)
{
	struct dma_chan *p = NULL;
	struct dma_slave_config config;

	if (chan == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct dma_chan *) (chan->dma_chan);

	config.direction              = cfg->direction;
	config.src_addr               = cfg->src_addr;
	config.dst_addr               = cfg->dst_addr;
	config.src_addr_width         = cfg->src_addr_width;
	config.dst_addr_width         = cfg->dst_addr_width;
	config.src_maxburst           = cfg->src_maxburst;
	config.dst_maxburst           = cfg->dst_maxburst;
	config.src_port_window_size   = cfg->src_port_window_size;
	config.dst_port_window_size   = cfg->dst_port_window_size;
	config.device_fc              = cfg->device_fc;
	config.slave_id               = cfg->slave_id;

	return dmaengine_slave_config(p, &config);
}
EXPORT_SYMBOL(os_dma_channel_config);

int os_dma_prep_cyclic(
		os_dma_chan_t *chan, unsigned long long buf_addr,
		unsigned int buf_len, unsigned int period_len,
		enum os_dma_direction dir, unsigned long flags,
		os_dma_callback callback, void *callback_param)
{
	struct dma_chan *p = NULL;
	struct dma_async_tx_descriptor *desc = NULL;

	if (chan == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct dma_chan *) (chan->dma_chan);
	desc = dmaengine_prep_dma_cyclic(p,
		(dma_addr_t)buf_addr, buf_len, period_len, dir, flags);
	if (!desc) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	desc->callback = callback;
	desc->callback_param = callback_param;
	chan->descriptor = (void *)desc;

	return 0;
}
EXPORT_SYMBOL(os_dma_prep_cyclic);

int os_dma_prep_memcpy(
		os_dma_chan_t *chan, unsigned long long dest,
		unsigned long long src, unsigned int len,
		unsigned long flags,
		os_dma_callback callback, void *callback_param)
{
	struct dma_chan *p = NULL;
	struct dma_async_tx_descriptor *desc = NULL;

	if (chan == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct dma_chan *) (chan->dma_chan);
	desc = dmaengine_prep_dma_memcpy(p,
		(dma_addr_t)dest, (dma_addr_t)src, len, flags);
	if (!desc) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	desc->callback = callback;
	desc->callback_param = callback_param;
	chan->descriptor = (void *)desc;

	return 0;
}
EXPORT_SYMBOL(os_dma_prep_memcpy);

os_dma_cookie_t os_dma_submit(os_dma_chan_t *chan)
{
	struct dma_async_tx_descriptor *desc;
	dma_cookie_t cookie;

	if (chan == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	desc = (struct dma_async_tx_descriptor *) (chan->descriptor);
	cookie = dmaengine_submit(desc);

	return (os_dma_cookie_t)cookie;
}
EXPORT_SYMBOL(os_dma_submit);

int os_dma_issue_pending(os_dma_chan_t *chan)
{
	struct dma_chan *p = NULL;

	if (chan == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct dma_chan *) (chan->dma_chan);
	dma_async_issue_pending(p);

	return 0;
}
EXPORT_SYMBOL(os_dma_issue_pending);

int os_dma_terminate_sync(os_dma_chan_t *chan)
{
	struct dma_chan *p = NULL;

	if (chan == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct dma_chan *) (chan->dma_chan);
	return dmaengine_terminate_sync(p);
}
EXPORT_SYMBOL(os_dma_terminate_sync);

int os_dma_terminate_async(os_dma_chan_t *chan)
{
	struct dma_chan *p = NULL;

	if (chan == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct dma_chan *) (chan->dma_chan);
	return dmaengine_terminate_async(p);
}
EXPORT_SYMBOL(os_dma_terminate_async);

/*
 * This function must only be called from non-atomic context and must not be
 * called from within a complete callback of a descriptor submitted on the same
 * channel.
 */
int os_dma_synchronize(os_dma_chan_t *chan)
{
	struct dma_chan *p = NULL;

	if (chan == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct dma_chan *) (chan->dma_chan);
	dmaengine_synchronize(p);

	return 0;
}
EXPORT_SYMBOL(os_dma_synchronize);

int os_dma_pause(os_dma_chan_t *chan)
{
	struct dma_chan *p = NULL;

	if (chan == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct dma_chan *) (chan->dma_chan);
	dmaengine_pause(p);

	return 0;
}
EXPORT_SYMBOL(os_dma_pause);

int os_dma_resume(os_dma_chan_t *chan)
{
	struct dma_chan *p = NULL;

	if (chan == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = (struct dma_chan *) (chan->dma_chan);
	dmaengine_resume(p);

	return 0;
}
EXPORT_SYMBOL(os_dma_resume);

int os_dma_cookie_status(os_dma_chan_t *chan, os_dma_cookie_t cookie,
			 os_dma_tx_state_t *state)
{
	struct dma_chan *p = NULL;
	struct dma_tx_state tx_state = {0};
	int status;

	if (chan == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return OS_DMA_ERROR;
	}
	p = (struct dma_chan *) (chan->dma_chan);
	status = dmaengine_tx_status(p, cookie, &tx_state);
	if (state) {
		state->last = tx_state.last;
		state->used = tx_state.used;
		state->residue = tx_state.residue;
	}

	return status;
}
EXPORT_SYMBOL(os_dma_cookie_status);

/*** irq ***/
int os_request_irq(unsigned int irq, os_irq_handler_t handler,
		   os_irq_handler_t thread_fn, const char *name, void *dev)
{
	unsigned long flags = IRQF_SHARED;

	return request_threaded_irq(irq, (irq_handler_t) handler,
				    (irq_handler_t) thread_fn, flags, name,
				    dev);
}
EXPORT_SYMBOL(os_request_irq);

void os_free_irq(unsigned int irq, void *dev)
{
	free_irq(irq, dev);
}
EXPORT_SYMBOL(os_free_irq);

int os_in_interrupt(void)
{
	return in_interrupt();
}
EXPORT_SYMBOL(os_in_interrupt);

/*** kfifo ****/
int os_kfifo_alloc(os_kfifo_t *kfifo, unsigned int size,
		unsigned int os_gfp_flag)
{
	int ret = 0;
	struct kfifo *p = NULL;

	if (kfifo == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	p = os_kmalloc(sizeof(struct __kfifo), os_gfp_flag);
	if (p == NULL) {
		os_printk("%s - os_kmalloc error!\n", __func__);
		return -1;
	}
	ret = kfifo_alloc(p, size, os_gfp_flag);
	if (ret == 0)
		kfifo->kfifo = p;

	return ret;
}
EXPORT_SYMBOL(os_kfifo_alloc);

void os_kfifo_free(os_kfifo_t *kfifo)
{
	struct kfifo *p = NULL;

	if (kfifo == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (struct kfifo *) (kfifo->kfifo);
		kfifo_free(p);

		os_kfree(p);
		kfifo->kfifo = NULL;
	}
}
EXPORT_SYMBOL(os_kfifo_free);

void os_kfifo_reset(os_kfifo_t *kfifo)
{
	struct kfifo *p = NULL;

	if (kfifo == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (struct kfifo *) (kfifo->kfifo);
		kfifo_reset(p);
	}
}
EXPORT_SYMBOL(os_kfifo_reset);

unsigned int os_kfifo_in(os_kfifo_t *kfifo,
	const void *buf, unsigned int len)
{
	struct kfifo *p = NULL;
	int ret = 0;

	if (kfifo == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (struct kfifo *) (kfifo->kfifo);
		ret = kfifo_in(p, buf, len);
	}

	return ret;
}
EXPORT_SYMBOL(os_kfifo_in);

unsigned int os_kfifo_out(os_kfifo_t *kfifo,
	void *buf, unsigned int len)
{
	struct kfifo *p = NULL;
	int ret = 0;

	if (kfifo == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (struct kfifo *) (kfifo->kfifo);
		ret = kfifo_out(p, buf, len);
	}

	return ret;
}
EXPORT_SYMBOL(os_kfifo_out);

unsigned int os_kfifo_in_spinlocked(os_kfifo_t *kfifo,
	const void *buf, unsigned int len, os_spinlock_t *lock)
{
	struct kfifo *p = NULL;
	int ret = 0;

	if (kfifo == NULL || lock == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (struct kfifo *) (kfifo->kfifo);
		ret = kfifo_in_spinlocked(p, buf, len, (spinlock_t *)(lock->lock));
	}

	return ret;
}
EXPORT_SYMBOL(os_kfifo_in_spinlocked);

unsigned int os_kfifo_out_spinlocked(os_kfifo_t *kfifo,
	void *buf, unsigned int len, os_spinlock_t *lock)
{
	struct kfifo *p = NULL;
	int ret = 0;

	if (kfifo == NULL || lock == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (struct kfifo *) (kfifo->kfifo);
		ret = kfifo_out_spinlocked(p, buf, len, (spinlock_t *)(lock->lock));
	}

	return ret;
}
EXPORT_SYMBOL(os_kfifo_out_spinlocked);

unsigned int os_kfifo_len(os_kfifo_t *kfifo)
{
	struct kfifo *p = NULL;
	int ret = 0;

	if (kfifo == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (struct kfifo *) (kfifo->kfifo);
		ret = kfifo_len(p);
	}

	return ret;
}
EXPORT_SYMBOL(os_kfifo_len);

unsigned int os_kfifo_avail(os_kfifo_t *kfifo)
{
	struct kfifo *p = NULL;
	int ret = 0;

	if (kfifo == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (struct kfifo *) (kfifo->kfifo);
		ret = kfifo_avail(p);
	}

	return ret;
}
EXPORT_SYMBOL(os_kfifo_avail);

int os_kfifo_is_full(os_kfifo_t *kfifo)
{
	struct kfifo *p = NULL;
	int ret = 0;

	if (kfifo == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (struct kfifo *) (kfifo->kfifo);
		ret = kfifo_is_full(p);
	}

	return ret;
}
EXPORT_SYMBOL(os_kfifo_is_full);

int os_kfifo_is_empty(os_kfifo_t *kfifo)
{
	struct kfifo *p = NULL;
	int ret = 0;

	if (kfifo == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
	} else {
		p = (struct kfifo *) (kfifo->kfifo);
		ret = kfifo_is_empty(p);
	}

	return ret;
}
EXPORT_SYMBOL(os_kfifo_is_empty);

/* the result of u64/u32. */
unsigned long long os_div_u64(unsigned long long dividend, unsigned int divisor)
{
	return div_u64(dividend, divisor);
}
EXPORT_SYMBOL(os_div_u64);

/* the result of s64/s32. */
long long os_div_s64(long long dividend, int divisor)
{
	return div_s64(dividend, divisor);
}
EXPORT_SYMBOL(os_div_s64);

/* the result of u64/u64. */
unsigned long long os_div64_u64(unsigned long long dividend,
				unsigned long long divisor)
{
	return div64_u64(dividend, divisor);
}
EXPORT_SYMBOL(os_div64_u64);

/* the result of s64/s64. */
long long os_div64_s64(long long dividend, long long divisor)
{
	return div64_s64(dividend, divisor);
}
EXPORT_SYMBOL(os_div64_s64);

/* the remainder of u64/u32. */
unsigned long long os_div_u64_rem(unsigned long long dividend,
				  unsigned int divisor)
{
	unsigned int remainder;

	div_u64_rem(dividend, divisor, &remainder);

	return remainder;
}
EXPORT_SYMBOL(os_div_u64_rem);

/* the remainder of s64/s32. */
long long os_div_s64_rem(long long dividend, int divisor)
{
	int remainder;

	div_s64_rem(dividend, divisor, &remainder);

	return remainder;
}
EXPORT_SYMBOL(os_div_s64_rem);

/* the remainder of u64/u64. */
unsigned long long os_div64_u64_rem(unsigned long long dividend,
				    unsigned long long divisor)
{
	unsigned long long remainder;

	div64_u64_rem(dividend, divisor, &remainder);

	return remainder;
}
EXPORT_SYMBOL(os_div64_u64_rem);

unsigned int os_random(void)
{
	return get_random_int();
}
EXPORT_SYMBOL(os_random);

unsigned int os_random_int(void)
{
	return get_random_int();
}
EXPORT_SYMBOL(os_random_int);

unsigned long os_random_long(void)
{
	return get_random_long();
}
EXPORT_SYMBOL(os_random_long);

/* device driver */
typedef struct _local_dev {
	struct os_dev os_dev;
	struct eimedia_device eimedia_dev;
} _local_dev_t;

struct os_private_data {
	struct os_file file;
	struct os_dev *dev;
	struct os_poll table;
};

void os_device_init(void)
{
	spin_lock_init(&dev_lock);
	spin_lock_init(&mem_lock);
}

void os_device_exit(void)
{
}

static int os_open(struct inode *inode, struct file *file)
{
	struct eimedia_device *eimedia = NULL;
	_local_dev_t *ld = NULL;
	struct os_private_data *pdata = NULL;

	if (!capable(CAP_SYS_RAWIO) || !capable(CAP_SYS_ADMIN))
		return -EPERM;

	eimedia = (struct eimedia_device *) file->private_data;
	if (eimedia == NULL) {
		os_printk("%s - get eimedia device error!\n", __func__);
		return -ENOMEM;
	}
	ld = container_of(eimedia, struct _local_dev, eimedia_dev);
	pdata =
	    (struct os_private_data *) os_kmalloc(sizeof(struct os_private_data),
					       os_gfp_kernel);
	if (pdata == NULL) {
		os_printk("%s - os_kmalloc error!\n", __func__);
		return -ENOMEM;
	}
	memset(pdata, 0, sizeof(struct os_private_data));

	file->private_data = pdata;
	pdata->dev = &(ld->os_dev);
	if (ld->os_dev.fops->open != NULL)
		return ld->os_dev.fops->open((void *) &(pdata->file));

	return 0;
}

static ssize_t os_read(struct file *file, char __user *buf, size_t size,
		       loff_t *offset)
{
	struct os_private_data *pdata = file->private_data;
	int ret = 0;

	if (pdata->dev->fops->read != NULL) {
		ret =
		    pdata->dev->fops->read(&(pdata->file), buf, (int) size,
					   (long *) offset);
	}

	return ret;
}

static ssize_t os_write(struct file *file, const char __user *buf, size_t size,
			loff_t *offset)
{
	struct os_private_data *pdata = file->private_data;
	int ret = 0;

	if (pdata->dev->fops->write != NULL) {
		ret =
		    pdata->dev->fops->write(&(pdata->file), buf, (int) size,
					    (long *) offset);
	}
	return ret;
}

static loff_t os_llseek(struct file *file, loff_t offset, int whence)
{
	struct os_private_data *pdata = file->private_data;
	int ret = 0;
	int whence_code = 0;

	switch (whence) {
	case SEEK_SET:
		whence_code = OSAL_SEEK_SET;
		break;
	case SEEK_CUR:
		whence_code = OSAL_SEEK_CUR;
		break;
	case SEEK_END:
		whence_code = OSAL_SEEK_END;
		break;
	default:
		whence_code = 0xff;	/* invalid whence_code */
	}

	if (whence_code != 0xff) {
		if (pdata->dev->fops->llseek != NULL) {
			ret =
			    pdata->dev->fops->llseek(&(pdata->file),
						     (long) offset,
						     OSAL_SEEK_SET);
		}
	}

	return (loff_t) ret;
}

static int os_release(struct inode *inode, struct file *file)
{
	int ret = 0;
	struct os_private_data *pdata = file->private_data;

	if (pdata->dev->fops->release != NULL) {
		ret = pdata->dev->fops->release(&(pdata->file));
		if (ret != 0)
			os_printk("%s - release failed!\n", __func__);
	}

	spin_lock(&dev_lock);
	os_kfree(file->private_data);
	file->private_data = NULL;
	spin_unlock(&dev_lock);

	return ret;
}


static long os_unlocked_ioctl(struct file *file, unsigned int cmd,
			      unsigned long arg)
{
	int ret = -1, is_vmalloc = 0;
	char sbuf[128];
	struct os_private_data *pdata = file->private_data;
	char *kbuf = NULL;
	unsigned long karg = arg;
	unsigned long *magic_prt = NULL;
	const size_t ioc_size = _IOC_SIZE(cmd);

	/* step1: parameter check */
	if (((ioc_size == 0) && (_IOC_DIR(cmd) != _IOC_NONE)))
		return -1;

	if ((_IOC_DIR(cmd) != _IOC_NONE)
	    && (((char *) (uintptr_t) arg) == NULL)) {
		os_printk("%s - Input param err,it is null!\n", __func__);
		return -1;
	}

	if (pdata->dev->fops->unlocked_ioctl == NULL) {
		os_printk("%s: Not support unlocked_ioctl!\n", __func__);
		return -1;
	}

	/* step2: parameter buffer prepare, accept input parameter */
	if (_IOC_DIR(cmd) != _IOC_NONE) {
		if ((ioc_size + sizeof(unsigned long)) <= sizeof(sbuf)) {
			karg = (unsigned long)sbuf;
		} else {
			kbuf = (char *) os_kmalloc(ioc_size + sizeof(unsigned long), os_gfp_kernel);
			if (kbuf == NULL) {
				is_vmalloc = 1;
				kbuf = (char *) os_vmalloc(ioc_size + sizeof(unsigned long));
				if (kbuf == NULL) {
					os_printk("%s - os_vmalloc failed!\n", __func__);
					return -1;
				}
			}
			karg = (unsigned long)kbuf;
		}
		magic_prt = (unsigned long *)(karg + ioc_size);
		*magic_prt = (unsigned long)karg;
	}

	if (_IOC_DIR(cmd) & _IOC_WRITE) {
		if (copy_from_user
		    ((char *)karg, (char *) (uintptr_t) arg, ioc_size)) {
			if (*magic_prt != (unsigned long)karg) {
				os_printk("%s - check kbuf failed 1, cmd: 0x%x, 0x%x!=0x%x\n",
					__func__, cmd, (unsigned int)*magic_prt, (unsigned int)karg);
			}
			if (is_vmalloc)
				os_vfree(kbuf);
			else
				os_kfree(kbuf);

			return -1;
		}
	}

	/* step3: do ioctl */
	ret = pdata->dev->fops->unlocked_ioctl(&(pdata->file), cmd, karg);

	/* step4: supply result and release resource */
	if (_IOC_DIR(cmd) & _IOC_READ) {
		if (ret == 0) {
			if (copy_to_user
			    ((char *) (uintptr_t) arg, (char *)karg, ioc_size)) {
				if (*magic_prt != (unsigned long)karg) {
					os_printk("%s - check kbuf failed 2, cmd: 0x%x, 0x%x!=0x%x\n",
						__func__, cmd, (unsigned int)*magic_prt, (unsigned int)karg);
				}
				if (is_vmalloc)
					os_vfree(kbuf);
				else
					os_kfree(kbuf);
				return -1;
			}
		}
	}

	if(kbuf != NULL) {
		if (*magic_prt != (unsigned long)kbuf) {
			os_printk("%s - check kbuf failed 3, cmd: 0x%x, 0x%x!=0x%p\n",
				__func__, cmd, (unsigned int)*magic_prt, kbuf);
		}
		if (is_vmalloc)
			os_vfree(kbuf);
		else
			os_kfree(kbuf);
	}

	return ret;
}

#ifdef CONFIG_COMPAT
static long os_compat_ioctl(struct file *file, unsigned int cmd,
			    unsigned long arg)
{
	int ret = -1;
	struct os_private_data *pdata = file->private_data;
	char *kbuf = NULL;

	if (((_IOC_SIZE(cmd) == 0) && (_IOC_DIR(cmd) != _IOC_NONE)))
		return -1;

	if ((_IOC_DIR(cmd) != _IOC_NONE)
	    && (((char *) (uintptr_t) arg) == NULL)) {
		os_printk("%s - Input param err,it is null!\n", __func__);
		return -1;
	}

	if (_IOC_DIR(cmd) == _IOC_NONE) {
		if (pdata->dev->fops->compat_ioctl == NULL)
			return -1;
		else
			ret = pdata->dev->fops->compat_ioctl(&(pdata->file),
							     cmd, arg);
	} else if (_IOC_DIR(cmd) == _IOC_WRITE) {
		kbuf = (char *) os_vmalloc(_IOC_SIZE(cmd));
		if (kbuf == NULL) {
			os_printk("%s - os_vmalloc failed!\n", __func__);
			return -1;
		}

		if (copy_from_user
		    (kbuf, (char *) (uintptr_t) arg, _IOC_SIZE(cmd))) {
			os_vfree(kbuf);
			return -1;
		}

		if (pdata->dev->fops->compat_ioctl == NULL) {
			os_vfree(kbuf);
			return -1;
		} else {
			ret =
			    pdata->dev->fops->compat_ioctl(&(pdata->file), cmd,
							   (unsigned
							    long) (uintptr_t)
							   kbuf);
		}
	} else if (_IOC_DIR(cmd) == _IOC_READ) {
		kbuf = os_vmalloc(_IOC_SIZE(cmd));
		if (kbuf == NULL) {
			os_printk("%s - os_vmalloc failed!\n", __func__);
			return -1;
		}
		if (pdata->dev->fops->compat_ioctl == NULL) {
			os_vfree(kbuf);
			return -1;
		} else {
			ret =
			    pdata->dev->fops->compat_ioctl(&(pdata->file), cmd,
							   (unsigned
							    long) (uintptr_t)
							   kbuf);
			if (ret == 0) {
				if (copy_to_user
				    ((char *) (uintptr_t) arg, kbuf,
				     _IOC_SIZE(cmd))) {
					os_vfree(kbuf);
					return -1;
				}
			}
		}
	} else if (_IOC_DIR(cmd) == (_IOC_READ + _IOC_WRITE)) {
		kbuf = os_vmalloc(_IOC_SIZE(cmd));
		if (kbuf == NULL) {
			os_printk("%s - os_vmalloc failed!\n", __func__);
			return -1;
		}

		if (copy_from_user
		    (kbuf, (char *) (uintptr_t) arg, _IOC_SIZE(cmd))) {
			os_vfree(kbuf);
			return -1;
		}

		if (pdata->dev->fops->compat_ioctl == NULL) {
			os_vfree(kbuf);
			return -1;
		} else {
			ret =
			    pdata->dev->fops->compat_ioctl(&(pdata->file), cmd,
							   (unsigned
							    long) (uintptr_t)
							   kbuf);
			if (ret == 0) {
				if (copy_to_user
				    ((char *) (uintptr_t) arg, kbuf,
				     _IOC_SIZE(cmd))) {
					os_vfree(kbuf);
					return -1;
				}
			}
		}
	}

	if (kbuf != NULL) {
		os_vfree(kbuf);
	}

	return ret;
}
#endif

static unsigned int os_poll(struct file *file, struct poll_table_struct *table)
{
	struct os_private_data *pdata = file->private_data;
	struct os_poll t;
	unsigned int ret = 0;

	t.poll_table = table;
	t.data = file;
	if (pdata->dev->fops->poll != NULL)
		ret = pdata->dev->fops->poll(&(pdata->file), &t);

	return ret;
}

static bool __valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
{
	bool valid = true;

	/* check up border */
	if ((pfn + (size >> PAGE_SHIFT)) > (1 + (PHYS_MASK >> PAGE_SHIFT))) {
		os_printk("%s()L%d, invalid addr range!\n", __func__, __LINE__);
		valid = false;
		goto exit;
	}

	/* check size */

exit:
	return valid;
}

static int os_mmap(struct file *file, struct vm_area_struct *vm)
{
	struct os_vm os_vm;
	struct os_private_data *pdata = file->private_data;

	os_vm.vm = vm;

	if (!__valid_mmap_phys_addr_range
	    (vm->vm_pgoff, vm->vm_end - vm->vm_start)) {
		os_printk("\n%s - invalid argument   size=%ld!!!\n", __func__,
			  vm->vm_end - vm->vm_start);
		return -EINVAL;
	}

	if (pdata->dev->fops->mmap != NULL) {
		return pdata->dev->fops->mmap(&(pdata->file), &os_vm,
					      vm->vm_start, vm->vm_end,
					      vm->vm_pgoff);
	}
	return 0;
}

static const struct file_operations os_fops = {
	.owner = THIS_MODULE,
	.open = os_open,
	.read = os_read,
	.write = os_write,
	.llseek = os_llseek,
	.unlocked_ioctl = os_unlocked_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl = os_compat_ioctl,
#endif
	.release = os_release,
	.poll = os_poll,
	.mmap = os_mmap,
};

static int os_pm_prepare(struct eimedia_device *eimedia)
{
	_local_dev_t *ld =
	    container_of(eimedia, struct _local_dev, eimedia_dev);

	if (ld->os_dev.pmops && ld->os_dev.pmops->pm_prepare)
		return ld->os_dev.pmops->pm_prepare(&(ld->os_dev));

	return 0;
}

static void os_pm_complete(struct eimedia_device *eimedia)
{
	_local_dev_t *ld =
	    container_of(eimedia, struct _local_dev, eimedia_dev);

	if (ld->os_dev.pmops && ld->os_dev.pmops->pm_complete)
		ld->os_dev.pmops->pm_complete(&(ld->os_dev));
}

static int os_pm_suspend(struct eimedia_device *eimedia)
{
	_local_dev_t *ld =
	    container_of(eimedia, struct _local_dev, eimedia_dev);

	if (ld->os_dev.pmops && ld->os_dev.pmops->pm_suspend)
		return ld->os_dev.pmops->pm_suspend(&(ld->os_dev));
	return 0;
}

static int os_pm_resume(struct eimedia_device *eimedia)
{
	_local_dev_t *ld =
	    container_of(eimedia, struct _local_dev, eimedia_dev);

	if (ld->os_dev.pmops && ld->os_dev.pmops->pm_resume)
		return ld->os_dev.pmops->pm_resume(&(ld->os_dev));

	return 0;
}

static int os_pm_freeze(struct eimedia_device *eimedia)
{
	_local_dev_t *ld =
	    container_of(eimedia, struct _local_dev, eimedia_dev);

	if (ld->os_dev.pmops && ld->os_dev.pmops->pm_freeze)
		return ld->os_dev.pmops->pm_freeze(&(ld->os_dev));

	return 0;
}

static int os_pm_restore(struct eimedia_device *eimedia)
{
	_local_dev_t *ld =
	    container_of(eimedia, struct _local_dev, eimedia_dev);

	if (ld->os_dev.pmops && ld->os_dev.pmops->pm_restore)
		return ld->os_dev.pmops->pm_restore(&(ld->os_dev));

	return 0;
}

static struct eimedia_pm_ops os_pmops = {
	.pm_prepare = os_pm_prepare,
	.pm_complete = os_pm_complete,
	.pm_suspend = os_pm_suspend,
	.pm_resume = os_pm_resume,
	.pm_freeze = os_pm_freeze,
	.pm_restore = os_pm_restore,
};

os_dev_t *os_device_create(const char *name)
{
	_local_dev_t *pdev = NULL;

	if (name == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return NULL;
	}
	pdev = (_local_dev_t *) os_kmalloc(sizeof(_local_dev_t), os_gfp_kernel);
	if (pdev == NULL) {
		os_printk("%s - os_kmalloc error!\n", __func__);
		return NULL;
	}
	memset(pdev, 0, sizeof(_local_dev_t));
	os_strncpy(pdev->os_dev.name, name, sizeof(pdev->os_dev.name) - 1);
	pdev->os_dev.dev = pdev;

	return &(pdev->os_dev);
}
EXPORT_SYMBOL(os_device_create);

int os_device_destroy(os_dev_t *os_dev)
{
	_local_dev_t *pdev = NULL;

	if (os_dev == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	pdev = os_dev->dev;
	if (pdev == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	os_kfree(pdev);
	return 0;
}
EXPORT_SYMBOL(os_device_destroy);

int os_device_register(os_dev_t *os_dev)
{
	struct eimedia_device *eimedia = NULL;

	if ((os_dev == NULL) || (os_dev->fops == NULL)) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	eimedia = &(((_local_dev_t *) (os_dev->dev))->eimedia_dev);
	eimedia->minor = os_dev->minor;

	eimedia->owner = THIS_MODULE;
	eimedia->fops = &os_fops;
	eimedia->pmops = &os_pmops;
	os_strncpy(eimedia->devfs_name, os_dev->name,
		   sizeof(eimedia->devfs_name) - 1);
	return eimedia_register(eimedia);
}
EXPORT_SYMBOL(os_device_register);

void os_device_deregister(os_dev_t *pdev)
{
	if (pdev == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return;
	}
	eimedia_deregister((struct eimedia_device *)
			   &(((_local_dev_t *) (pdev->dev))->eimedia_dev));
}
EXPORT_SYMBOL(os_device_deregister);

void os_poll_wait(os_poll_t *table, os_wait_t *wait)
{
	poll_wait((struct file *) table->data,
		  (wait_queue_head_t *) (wait->wait), table->poll_table);

}
EXPORT_SYMBOL(os_poll_wait);
int os_platform_driver_register(void *drv)
{
	return __platform_driver_register((struct platform_driver *) drv,
					  THIS_MODULE);
}
EXPORT_SYMBOL(os_platform_driver_register);

void os_platform_driver_unregister(void *drv)
{
	return platform_driver_unregister((struct platform_driver *) drv);
}
EXPORT_SYMBOL(os_platform_driver_unregister);

void *os_platform_get_resource_byname(void *dev, unsigned int type,
				      const char *name)
{
	return (void *) platform_get_resource_byname((struct platform_device *)
						     dev, type, name);
}
EXPORT_SYMBOL(os_platform_get_resource_byname);

void *os_platform_get_resource(void *dev, unsigned int type, unsigned int num)
{
	return (void *) platform_get_resource((struct platform_device *) dev,
					      type, num);
}
EXPORT_SYMBOL(os_platform_get_resource);

int os_platform_get_irq(void *dev, unsigned int num)
{
	return platform_get_irq((struct platform_device *) dev, num);
}
EXPORT_SYMBOL(os_platform_get_irq);

int os_platform_get_irq_byname(void *dev, const char *name)
{
	return platform_get_irq_byname((struct platform_device *) dev, name);
}
EXPORT_SYMBOL(os_platform_get_irq_byname);

#define ROOT_PROC_NAME "mdp"

static struct os_list_head list;
static os_proc_entry_t *root_proc_entry;

static int os_seq_show(struct seq_file *s, void *p)
{
	os_proc_entry_t *oldsentry = s->private;
	os_proc_entry_t entry;

	if (oldsentry == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	memset(&entry, 0, sizeof(os_proc_entry_t));

	entry.seqfile = s;
	entry.private_data = oldsentry->private_data;
	if ((oldsentry->fops) && (oldsentry->fops->read))
		oldsentry->fops->read(&entry);

	return 0;
}

int os_seq_printf(os_proc_entry_t *entry, const char *fmt, ...)
{
	struct seq_file *s = (struct seq_file *) (entry->seqfile);
	va_list args;
	int r = 0;

	va_start(args, fmt);
	seq_vprintf(s, fmt, args);
	va_end(args);

	return r;
}
EXPORT_SYMBOL(os_seq_printf);

static ssize_t os_proc_write(struct file *file, const char __user *buf,
			     size_t count, loff_t *ppos)
{
	os_proc_entry_t *item = PDE_DATA(file_inode(file));

	if ((item != NULL) && (item->fops) && (item->fops->write != NULL))
		return item->fops->write(item, buf, count, (long long *) ppos);

	return -EINVAL;
}

static int os_proc_open(struct inode *inode, struct file *file)
{
	os_proc_entry_t *sentry = PDE_DATA(inode);

	if ((sentry != NULL) && (sentry->fops)
	    && (sentry->fops->open != NULL))
		sentry->fops->open(sentry);

	return single_open(file, os_seq_show, sentry);
}

static int os_proc_release(struct inode *inode, struct file *file)
{
	os_proc_entry_t *sentry = PDE_DATA(inode);

	if ((sentry != NULL) && (sentry->fops)
	    && (sentry->fops->close != NULL))
		sentry->fops->close(sentry);

	return single_release(inode, file);
}

static const struct file_operations os_proc_ops = {
	.owner = THIS_MODULE,
	.open = os_proc_open,
	.read = seq_read,
	.write = os_proc_write,
	.llseek = seq_lseek,
	.release = os_proc_release,
};

os_proc_entry_t *os_proc_create(const char *name, os_proc_entry_t *parent,
				os_proc_fops_t *fops)
{
	struct proc_dir_entry *e = NULL;
	struct proc_dir_entry *pe = NULL;
	os_proc_entry_t *entry = NULL;

	if (name == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		goto exit;
	}
	/* all subdevice share the same parent entry */
	parent = root_proc_entry;
	if (parent != NULL)
		pe = parent->entry;

	entry = os_kmalloc(sizeof(os_proc_entry_t), os_gfp_kernel);
	if (entry == NULL) {
		os_printk("%s - os_kmalloc failed!\n", __func__);
		goto exit;
	}
	os_memset(entry, 0, sizeof(os_proc_entry_t));
	os_strncpy(entry->name, name, sizeof(entry->name) - 1);

	e = proc_create_data(name, 0, pe, &os_proc_ops, entry);

	if (e == NULL) {
		os_printk("%s - create_proc_entry failed!\n", __func__);
		os_kfree(entry);
		entry = NULL;
		goto exit;
	}
	entry->fops = fops;
	entry->entry = e;

exit:
	return entry;
}
EXPORT_SYMBOL(os_proc_create);

void os_proc_remove(os_proc_entry_t *entry, os_proc_entry_t *parent)
{
	struct proc_dir_entry *pe = NULL;

	if (entry == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return;
	}
	if (entry->name == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return;
	}
	/* all subentry share the same parent entry except the root one */
	if (entry != root_proc_entry)
		parent = root_proc_entry;

	if (parent != NULL)
		pe = parent->entry;

	remove_proc_entry(entry->name, pe);
	os_kfree(entry);
}
EXPORT_SYMBOL(os_proc_remove);

os_proc_entry_t *os_proc_mkdir(const char *name, os_proc_entry_t *parent)
{
	struct proc_dir_entry *e = NULL;
	struct proc_dir_entry *pe = NULL;
	os_proc_entry_t *entry = NULL;

	entry = os_kmalloc(sizeof(os_proc_entry_t), os_gfp_kernel);
	if (entry == NULL) {
		os_printk("%s - os_kmalloc failed!\n", __func__);
		return NULL;
	}
	os_memset(entry, 0, sizeof(os_proc_entry_t));

	os_strncpy(entry->name, name, sizeof(entry->name) - 1);

	if (parent != NULL)
		pe = parent->entry;

	e = proc_mkdir_data(name, 0, pe, entry);
	if (e == NULL) {
		os_printk("%s - proc_mkdir failed!\n", __func__);
		os_kfree(entry);
		entry = NULL;
		return NULL;
	}
	entry->entry = e;

	return entry;
}

void os_proc_init(void)
{
	OSAL_INIT_LIST_HEAD(&list);
	root_proc_entry = os_proc_mkdir(ROOT_PROC_NAME, OSAL_NULL);
	if (root_proc_entry == OSAL_NULL)
		os_printk("test init, proc mkdir error!\n");
}
void os_proc_exit(void)
{
	os_proc_remove(root_proc_entry, OSAL_NULL);
}

/* strings */
char *os_strcpy(char *dest, const char *src)
{
	return strcpy(dest, src);
}
EXPORT_SYMBOL(os_strcpy);
char *os_strncpy(char *dest, const char *src, int count)
{
	return strncpy(dest, src, count);
}
EXPORT_SYMBOL(os_strncpy);
int os_strlcpy(char *dest, const char *src, int size)
{
	return strlcpy(dest, src, size);
}
EXPORT_SYMBOL(os_strlcpy);
char *os_strcat(char *dest, const char *src)
{
	return strcat(dest, src);
}
EXPORT_SYMBOL(os_strcat);
char *os_strncat(char *dest, const char *src, int count)
{
	return strncat(dest, src, count);
}
EXPORT_SYMBOL(os_strncat);
int os_strlcat(char *dest, const char *src, int count)
{
	return strlcat(dest, src, count);
}
EXPORT_SYMBOL(os_strlcat);
int os_strcmp(const char *cs, const char *ct)
{
	return strcmp(cs, ct);
}
EXPORT_SYMBOL(os_strcmp);
int os_strncmp(const char *cs, const char *ct, int count)
{
	return strncmp(cs, ct, count);
}
EXPORT_SYMBOL(os_strncmp);
int os_strcasecmp(const char *s1, const char *s2)
{
	return strcasecmp(s1, s2);
}
EXPORT_SYMBOL(os_strcasecmp);
int os_strncasecmp(const char *s1, const char *s2, int n)
{
	return strncasecmp(s1, s2, n);
}
EXPORT_SYMBOL(os_strncasecmp);
char *os_strchr(const char *s, int c)
{
	return strchr(s, c);
}
EXPORT_SYMBOL(os_strchr);
char *os_strnchr(const char *s, int count, int c)
{
	return strnchr(s, count, c);
}
EXPORT_SYMBOL(os_strnchr);
char *os_strrchr(const char *s, int c)
{
	return strrchr(s, c);
}
EXPORT_SYMBOL(os_strrchr);
char *os_strstr(const char *s1, const char *s2)
{
	return strstr(s1, s2);
}
EXPORT_SYMBOL(os_strstr);
char *os_strnstr(const char *s1, const char *s2, int len)
{
	return strnstr(s1, s2, len);
}
EXPORT_SYMBOL(os_strnstr);
int os_strlen(const char *s)
{
	return strlen(s);
}
EXPORT_SYMBOL(os_strlen);
int os_strnlen(const char *s, int count)
{
	return strnlen(s, count);
}
EXPORT_SYMBOL(os_strnlen);
char *os_strpbrk(const char *cs, const char *ct)
{
	return strpbrk(cs, ct);
}
EXPORT_SYMBOL(os_strpbrk);
char *os_strsep(char **s, const char *ct)
{
	return strsep(s, ct);
}
EXPORT_SYMBOL(os_strsep);
int os_strspn(const char *s, const char *accept)
{
	return strspn(s, accept);
}
EXPORT_SYMBOL(os_strspn);
int os_strcspn(const char *s, const char *reject)
{
	return strcspn(s, reject);
}
EXPORT_SYMBOL(os_strcspn);
void *os_memset(void *str, int c, int count)
{
	return memset(str, c, count);
}
EXPORT_SYMBOL(os_memset);
void *os_memcpy(void *dest, const void *src, int count)
{
	return memcpy(dest, src, count);
}
EXPORT_SYMBOL(os_memcpy);
void *os_memmove(void *dest, const void *src, int count)
{
	return memmove(dest, src, count);
}
EXPORT_SYMBOL(os_memmove);
void *os_memscan(void *addr, int c, int size)
{
	return memscan(addr, c, size);
}
EXPORT_SYMBOL(os_memscan);
int os_memcmp(const void *cs, const void *ct, int count)
{
	return memcmp(cs, ct, count);
}
EXPORT_SYMBOL(os_memcmp);
void *os_memchr(const void *s, int c, int n)
{
	return memchr(s, c, n);
}
EXPORT_SYMBOL(os_memchr);
void *os_memchr_inv(const void *start, int c, int bytes)
{
	return memchr_inv(start, c, bytes);
}
EXPORT_SYMBOL(os_memchr_inv);
unsigned long long os_strtoull(const char *cp, char **endp, unsigned int base)
{
	return simple_strtoull(cp, endp, base);
}
EXPORT_SYMBOL(os_strtoull);
unsigned long os_strtoul(const char *cp, char **endp, unsigned int base)
{
	return simple_strtoul(cp, endp, base);
}
EXPORT_SYMBOL(os_strtoul);
long os_strtol(const char *cp, char **endp, unsigned int base)
{
	return simple_strtol(cp, endp, base);
}
EXPORT_SYMBOL(os_strtol);
long long os_strtoll(const char *cp, char **endp, unsigned int base)
{
	return simple_strtoll(cp, endp, base);
}
EXPORT_SYMBOL(os_strtoll);
char *os_strim(char *s)
{
	return strim(s);
}
EXPORT_SYMBOL(os_strim);
int os_snprintf(char *buf, int size, const char *fmt, ...)
{
	va_list args;
	int i;

	va_start(args, fmt);
	i = vsnprintf(buf, size, fmt, args);
	va_end(args);

	return i;
}
EXPORT_SYMBOL(os_snprintf);
int os_scnprintf(char *buf, int size, const char *fmt, ...)
{
	va_list args;
	int i;

	va_start(args, fmt);
	i = vscnprintf(buf, size, fmt, args);
	va_end(args);

	return i;
}
EXPORT_SYMBOL(os_scnprintf);
int os_sprintf(char *buf, const char *fmt, ...)
{
	va_list args;
	int i;

	va_start(args, fmt);
	i = vsnprintf(buf, INT_MAX, fmt, args);
	va_end(args);

	return i;
}
EXPORT_SYMBOL(os_sprintf);
int os_sscanf(const char *buf, const char *fmt, ...)
{
	va_list args;
	int i;

	va_start(args, fmt);
	i = vsscanf(buf, fmt, args);
	va_end(args);

	return i;
}
EXPORT_SYMBOL(os_sscanf);

int os_vsnprintf(char *str, int size, const char *fmt, os_va_list args)
{
	return vsnprintf(str, size, fmt, args);
}
EXPORT_SYMBOL(os_vsnprintf);

/* thread */
os_task_t *os_kthread_create(int (*threadfn) (void *data),
			     void *data, const char *name)
{
	struct task_struct *t = NULL;
	os_task_t *p = NULL;

	p = (os_task_t *) os_kmalloc(sizeof(os_task_t), os_gfp_kernel);
	if (p == NULL) {
		os_printk("%s - os_kmalloc error!\n", __func__);
		return NULL;
	}
	memset(p, 0, sizeof(os_task_t));

	t = kthread_run(threadfn, data, name);
	if (IS_ERR(t)) {
		os_printk("%s - kthread create error!\n", __func__);
		os_kfree(p);
		return NULL;
	}
	p->task_struct = t;

	return p;
}
EXPORT_SYMBOL(os_kthread_create);

void os_kthread_destroy(os_task_t *task, unsigned int wanna_stop)
{
	if (task == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return;
	}

	if (!IS_ERR_OR_NULL(task->task_struct) && (wanna_stop != 0))
		kthread_stop((struct task_struct *) (task->task_struct));

	task->task_struct = NULL;
	os_kfree(task);
}
EXPORT_SYMBOL(os_kthread_destroy);

char os_kthread_should_stop(void)
{
	return kthread_should_stop();
}
EXPORT_SYMBOL(os_kthread_should_stop);

typedef struct _local_work {
	struct work_struct work;
	struct os_work_struct *os_work;
} _local_work_t;

static void os_work_func(struct work_struct *work)
{
	_local_work_t *lw = container_of(work, _local_work_t, work);
	struct os_work_struct *ow = lw->os_work;

	if ((ow != NULL) && (ow->func != NULL))
		ow->func(ow);
}

int os_init_work(struct os_work_struct *work, os_work_func_t func)
{
	_local_work_t *lw = NULL;

	lw = (_local_work_t *) os_kmalloc(sizeof(_local_work_t), os_gfp_kernel);
	if (lw == NULL) {
		os_printk("%s os_kmalloc failed!\n", __func__);
		return -1;
	}

	INIT_WORK(&lw->work, os_work_func);
	work->work = lw;
	work->func = func;
	lw->os_work = work;

	return 0;
}
EXPORT_SYMBOL(os_init_work);

int os_schedule_work(struct os_work_struct *work)
{
	_local_work_t *lw = NULL;

	if ((work != NULL) && (work->work != NULL)) {
		lw = (_local_work_t *) work->work;

		return (int) schedule_work(&lw->work);
	} else {
		return (int) false;
	}
}
EXPORT_SYMBOL(os_schedule_work);

int os_flush_work(struct os_work_struct *work)
{
	_local_work_t *lw = NULL;

	if ((work != NULL) && (work->work != NULL)) {
		lw = (_local_work_t *) work->work;

		return (int) flush_work(&lw->work);
	} else {
		return (int) false;
	}

}
EXPORT_SYMBOL(os_flush_work);

void os_destroy_work(struct os_work_struct *work)
{
	_local_work_t *lw = NULL;

	if ((work != NULL) && (work->work != NULL)) {
		lw = (_local_work_t *) work->work;
		os_kfree(lw);
		work->work = NULL;
	}
}
EXPORT_SYMBOL(os_destroy_work);

/* timer */
typedef struct _local_timer {
	union {
		struct timer_list timer;
		struct hrtimer h;
	};
	os_timer_t *os_timer;
} _local_timer_t;

static void os_timer_fun(struct timer_list *t)
{
	_local_timer_t *lt = container_of(t, _local_timer_t, timer);
	os_timer_t *timer = (os_timer_t *) lt->os_timer;

	if (timer && timer->function)
		timer->function(timer->data);
}

int os_timer_init(os_timer_t *timer, void (*fun) (unsigned long),
		  unsigned long data)
{
	struct timer_list *t = NULL;
	_local_timer_t *lt = NULL;

	if (timer == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}

	lt = (_local_timer_t *) os_kmalloc(sizeof(_local_timer_t), os_gfp_kernel);
	if (lt == NULL) {
		os_printk("%s - os_kmalloc error!\n", __func__);
		return -1;
	}
	lt->os_timer = timer;
	t = &lt->timer;

	timer_setup(t, os_timer_fun, 0);
	timer->timer = lt;
	timer->function = fun;
	timer->data = data;

	return 0;
}
EXPORT_SYMBOL(os_timer_init);

int os_set_timer(os_timer_t *timer, unsigned long timeout_ms)
{
	struct timer_list *t = NULL;
	_local_timer_t *lt = NULL;

	if ((timer == NULL) || (timer->timer == NULL)
	    || (timer->function == NULL) || (timeout_ms == 0)) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	lt = (_local_timer_t *) timer->timer;
	t = &lt->timer;

	return mod_timer(t, jiffies + msecs_to_jiffies(timeout_ms) - 1);
}
EXPORT_SYMBOL(os_set_timer);

int os_del_timer(os_timer_t *timer)
{
	struct timer_list *t = NULL;
	_local_timer_t *lt = NULL;

	if ((timer == NULL) || (timer->timer == NULL)
	    || (timer->function == NULL)) {
		os_printk("%s - parameter invalid!\n", __func__);
		return -1;
	}
	lt = (_local_timer_t *) timer->timer;
	t = &lt->timer;

	return del_timer(t);
}
EXPORT_SYMBOL(os_del_timer);

int os_timer_destroy(os_timer_t *timer)
{
	struct timer_list *t = timer->timer;
	_local_timer_t *lt = NULL;

	lt = (_local_timer_t *) timer->timer;
	t = &lt->timer;

	del_timer(t);
	os_kfree(lt);
	timer->timer = NULL;
	return 0;
}
EXPORT_SYMBOL(os_timer_destroy);

/* hrtimer */
static enum hrtimer_restart os_hrtimer_fun(struct hrtimer *t)
{
	_local_timer_t *lt = container_of(t, _local_timer_t, h);
	os_timer_t *timer = (os_timer_t *)lt->os_timer;

	if (timer && timer->function)
		timer->function(timer->data);

	/*
	 * normally in linux driver, hrtimer restarted in this way:
	 *     enum hrtimer_restart os_hrtimer_fun(struct hrtimer *t)
	 *     {
	 *         ...
	 *         if (need_restart) <-- check if need restart
	 *                 hrtimer_forward_now(t, timeout_ms);
	 *         return need_restart ? HRTIMER_RESTART : HRTIMER_NORESTART;
	 *     }
	 *
	 * in mdp here, hrtimer restarted in this way:
	 *     enum hrtimer_restart os_hrtimer_fun(struct hrtimer *t)
	 *     {
	 *         if (timer && timer->function)
	 *                 timer->function(timer->data);
	 *         ...
	 *         return HRTIMER_NORESTART;
	 *     }
	 *     void function(unsigned long data)
	 *     {
	 *         ...
	 *         os_set_hrtimer(timer, timeout_ms); <-- restart the hrtimer
	 *     }
	 */
	return HRTIMER_NORESTART;
}

int os_hrtimer_init(os_timer_t *timer, void (*fun)(unsigned long),
		unsigned long data)
{
	_local_timer_t *lt;

	lt = os_kzalloc(sizeof(_local_timer_t), os_gfp_kernel);
	if (NULL == lt) {
		os_printk("%s:%d: os_kzalloc error!\n", __func__, __LINE__);
		return -1;
	}

	hrtimer_init(&lt->h, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	lt->h.function = os_hrtimer_fun;

	lt->os_timer = timer;

	timer->function = fun;
	timer->data = data;

	timer->timer = lt;
	return 0;
}
EXPORT_SYMBOL(os_hrtimer_init);

int os_set_hrtimer(os_timer_t *timer, unsigned long timeout_ms)
{
	_local_timer_t *lt = NULL;
	ktime_t tim;

	if (!timer || !timer->timer || !timer->function || !timeout_ms) {
		os_printk("%s:%d: parameter invalid!\n", __func__, __LINE__);
		return -1;
	}

	lt = (_local_timer_t *)timer->timer;
	if (NULL == lt) {
		os_printk("%s:%d: timer invalid!\n", __func__, __LINE__);
		return -1;
	}

	tim = ms_to_ktime((u64)timeout_ms);

	hrtimer_start(&lt->h, tim, HRTIMER_MODE_REL);
	return 0;
}
EXPORT_SYMBOL(os_set_hrtimer);

/**
 * cancel a timer and wait for the handler to finish
 * @timer: the timer handle
 *
 * Returns:
 *  0 when the timer was not active
 *  1 when the timer was active
 * -1 timer invalid
 */
int os_del_hrtimer(os_timer_t *timer)
{
	_local_timer_t *lt = NULL;

	if (!timer || !timer->timer || !timer->function) {
		os_printk("%s:%d: parameter invalid!\n", __func__, __LINE__);
		return -1;
	}

	lt = (_local_timer_t *)timer->timer;
	if (NULL == lt) {
		os_printk("%s:%d: timer invalid!\n", __func__, __LINE__);
		return -1;
	}

	return hrtimer_cancel(&lt->h);
}
EXPORT_SYMBOL(os_del_hrtimer);

int os_hrtimer_destroy(os_timer_t *timer)
{
	_local_timer_t *lt = NULL;

	if ((NULL == timer) || (NULL == timer->timer) || (NULL == timer->function)) {
		os_printk("%s:%d: parameter invalid!\n", __func__, __LINE__);
		return -1;
	}

	lt = (_local_timer_t *)timer->timer;

	hrtimer_cancel(&lt->h);

	os_kfree(lt);

	timer->timer = NULL;
	timer->function = NULL;
	timer->data = 0;
	return 0;
}
EXPORT_SYMBOL(os_hrtimer_destroy);

unsigned long os_msleep(unsigned int msecs)
{
	return msleep_interruptible(msecs);
}
EXPORT_SYMBOL(os_msleep);

void os_usleep_range(unsigned long min, unsigned long max)
{
	usleep_range(min, max);
}
EXPORT_SYMBOL(os_usleep_range);

void os_udelay(unsigned int usecs)
{
	udelay(usecs);
}
EXPORT_SYMBOL(os_udelay);

void os_mdelay(unsigned int msecs)
{
	mdelay(msecs);
}
EXPORT_SYMBOL(os_mdelay);

void os_getjiffies(unsigned long long *pjiffies)
{
	*pjiffies = jiffies;
}
EXPORT_SYMBOL(os_getjiffies);

unsigned int os_get_tickcount(void)
{
	return jiffies_to_msecs(jiffies);
}
EXPORT_SYMBOL(os_get_tickcount);

unsigned int os_local_clock(void)
{
	return local_clock();
}
EXPORT_SYMBOL(os_local_clock);

unsigned long os_msecs_to_jiffies(const unsigned int m)
{
	return msecs_to_jiffies(m);
}
EXPORT_SYMBOL(os_msecs_to_jiffies);

unsigned int os_jiffies_to_msecs(const unsigned long long j)
{
	return jiffies_to_msecs(j);
}
EXPORT_SYMBOL(os_jiffies_to_msecs);

void os_gettimeofday(os_timeval_t *tv)
{
	struct timeval t;

	if (tv == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return;
	}
	do_gettimeofday(&t);

	tv->tv_sec = t.tv_sec;
	tv->tv_usec = t.tv_usec;
}
EXPORT_SYMBOL(os_gettimeofday);

void os_gettimestamp(os_timeval_t *tv)
{
	struct timespec ts;

	if (tv == NULL) {
		os_printk("%s - parameter invalid!\n", __func__);
		return;
	}

	ktime_get_ts(&ts);
	tv->tv_sec = ts.tv_sec;
	tv->tv_usec = ts.tv_nsec / 1000L;
}
EXPORT_SYMBOL(os_gettimestamp);

static void os_from_tm(os_rtc_time_t *to, struct rtc_time *from)
{
	to->tm_sec = from->tm_sec;
	to->tm_min = from->tm_min;
	to->tm_hour = from->tm_hour;
	to->tm_mday = from->tm_mday;
	to->tm_mon = from->tm_mon;
	to->tm_year = from->tm_year;
	to->tm_wday = from->tm_wday;
	to->tm_yday = from->tm_yday;
	to->tm_isdst = from->tm_isdst;
}

static void os_to_tm(struct rtc_time *to, os_rtc_time_t *from)
{
	to->tm_sec = from->tm_sec;
	to->tm_min = from->tm_min;
	to->tm_hour = from->tm_hour;
	to->tm_mday = from->tm_mday;
	to->tm_mon = from->tm_mon;
	to->tm_year = from->tm_year;
	to->tm_wday = from->tm_wday;
	to->tm_yday = from->tm_yday;
	to->tm_isdst = from->tm_isdst;
}

void os_rtc_time_to_tm(unsigned long time, os_rtc_time_t *tm)
{
	struct rtc_time _tm = { 0 };

	rtc_time_to_tm(time, &_tm);

	os_from_tm(tm, &_tm);
}
EXPORT_SYMBOL(os_rtc_time_to_tm);

void os_rtc_tm_to_time(os_rtc_time_t *tm, unsigned long *time)
{
	struct rtc_time _tm;

	os_to_tm(&_tm, tm);
	rtc_tm_to_time(&_tm, time);
}
EXPORT_SYMBOL(os_rtc_tm_to_time);

int os_rtc_valid_tm(struct os_rtc_time *tm)
{
	struct rtc_time _tm;

	os_to_tm(&_tm, tm);

	return rtc_valid_tm(&_tm);
}
EXPORT_SYMBOL(os_rtc_valid_tm);

/* klib */
void *os_klib_fopen(const char *filename, int flags, int mode)
{
	struct file *filp = filp_open(filename, flags, mode);

	return (IS_ERR(filp)) ? NULL : (void *) filp;
}
EXPORT_SYMBOL(os_klib_fopen);

void os_klib_fclose(void *filp)
{
	if (filp != NULL)
		filp_close((struct file *) filp, NULL);
}
EXPORT_SYMBOL(os_klib_fclose);

int os_klib_fwrite(const char *buf, int count, void *filp)
{
	struct file *file = (struct file *) filp;

	if (filp == NULL)
		return -ENOENT;

	if (buf == NULL)
		return -EINVAL;

	return __kernel_write(file, buf, count, &file->f_pos);
}
EXPORT_SYMBOL(os_klib_fwrite);

int os_klib_fread(char *buf, unsigned int count, void *filp)
{
	struct file *file = (struct file *) filp;

	if (filp == NULL)
		return -ENOENT;

	if (buf == NULL)
		return -EINVAL;

	return kernel_read(file, buf, count, &file->f_pos);
}
EXPORT_SYMBOL(os_klib_fread);
